package com.qdu.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.mysql.cj.util.StringUtils;
import com.qdu.commons.RedisKey;
import com.qdu.commons.Result;
import com.qdu.entity.User;
import com.qdu.vo.WXAuth;
import com.qdu.entity.Weixin;
import com.qdu.vo.WxUserInfo;
import com.qdu.mapper.WeixinMapper;
import com.qdu.service.IWeixinService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.jws.soap.SOAPBinding;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author:sanShi
 * @Description:{}
 * @date :2022/03/08
 */
@Slf4j
@Service
public class WeixinServiceImpl extends ServiceImpl<WeixinMapper, Weixin> implements IWeixinService {


    @Value("${weixin.appid}")
    private String appid;

    @Value("${weixin.secret}")
    private String secret;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    WxService wxService;

    @Autowired
    UserServiceImpl userService;


    @Override
    public String getSessionId(String code) {

        String url = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
        String replaceUrl = url.replace("{0}", appid).replace("{1}", secret).replace("{2}", code);
        String res = HttpUtil.get(replaceUrl);

        log.info("发送链接后获得的数据{}",res);
        String s = UUID.randomUUID().toString();

        redisTemplate.opsForValue().set(RedisKey.WX_SESSION_ID + s, res);
        redisTemplate.opsForValue().set("openId" + s,(String) JSON.parseObject(res).get("openid"));
        return s;
    }

    @Override
    public Result authLogin(WXAuth wxAuth) {
        try {
            String wxRes = wxService.wxDecrypt(wxAuth.getEncryptedData(), wxAuth.getSessionId(), wxAuth.getIv());
            log.info("登录用户信息："+wxRes);
            WxUserInfo wxUserInfo = JSON.parseObject(wxRes,WxUserInfo.class);

            String openId = redisTemplate.opsForValue().get("openId"+wxAuth.getSessionId()).toString();

            if(!userService.isUnion(openId)){
                User user=new User();
                user.setOpenId(openId);
                user.setAvatarUrl(wxUserInfo.getAvatarUrl());
                user.setName(wxUserInfo.getNickName());
                log.info("登录用户信息：{}"+user);
                try{
                    //新用户将绑定入库
                    saveNewUser(user);
                    //Spring只支持抛出org.springframework.dao.DataAccessException异常，
                    //该异常与实际异常java.sql.SQLSyntaxErrorException父类不相同，因此无法捕获；
                }catch (DataAccessException exception){
                    System.err.println(exception);
                    //异常说明，该账户已经被注册
                    User result=userService.getOne(new QueryWrapper<User>().eq("openId",openId));
                    //如果没有解绑定，则不能继续进行
                    if (!StringUtils.isNullOrEmpty(result.getOpenId())) {
                        return Result.USER_HAS_REGISTERED();
                    }
                    result.setOpenId(openId);
                    result.setAvatarUrl(wxUserInfo.getAvatarUrl());
                    userService.updateById(result);
                }

            }
            User res = userService.getOne(new QueryWrapper<User>().eq("openId",openId));
            redisTemplate.opsForZSet().incrementScore(RedisKey.RANK, res.getId(), res.getPoint());
            redisTemplate.opsForHash().put(RedisKey.ALL_USER_INFO, res.getId().toString(), res);
            return Result.SUCCESS(res);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.FAIL();
    }

    /**
     * 新用户注册&更新缓存
     * @param user
     * @throws DataAccessException
     */
    private void saveNewUser(User user) throws DataAccessException{
        //入库
        userService.save(user);
        //更新缓存
        redisTemplate.opsForHash().put(RedisKey.ALL_USER_INFO , user.getId().toString(), user);
    }
}